package com.sinosoft.dsp.system.to.helper;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.primefaces.json.JSONArray;
import org.primefaces.json.JSONException;
import org.primefaces.json.JSONObject;

import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.to.GenericTO;
import com.sinosoft.dsp.system.to.IGenericTO;
import com.sinosoft.dsp.system.to.attribute.Attribute;
import com.sinosoft.dsp.system.to.exception.SinoAttributeException;
import com.sinosoft.dsp.system.utils.Const;
import com.sinosoft.dsp.system.utils.ReflectionUtils;

/**
 * 用于生成TO的帮助类
 * 
 * @author 潘巍（Peter Pan）
 * @since 2011-2-4 下午09:40:19
 */
public class ToHelper {

	private static final long serialVersionUID = 1714418459730516244L;

	public static final String ATTRIBUTE_CONTENT = "content";

	public static final String ATTRIBUTE_CONTENT_PREFIX = "content[0]->";

	private static final Log log = Log.getLog(ToHelper.class.getName());

	/**
	 * 创建一个通用To对象
	 * 
	 * @return
	 * @throws SinoAttributeException
	 */
	public static IGenericTO createGenericTO() throws SinoAttributeException {
		try {
			IGenericTO to = (IGenericTO) ReflectionUtils
					.newInstance(GenericTO.class);
			return to;
		} catch (Exception e) {
			log.error("创建通用TO出现错误(createGenericTO)");
			throw new SinoAttributeException("创建通用TO出现错误(createGenericTO)");
		}
	}

	/**
	 * 通过TO对象创建JSON对象
	 * 
	 * @param to
	 * @return
	 * @throws SinoAttributeException
	 */
	public static JSONObject createJSONObject(IGenericTO to)
			throws SinoAttributeException {
		try {
			JSONObject json = new JSONObject();
			if (to != null) {
				List<Attribute<?>> attrs = to.getAttributes();
				if (attrs != null && attrs.size() > 0) {
					for (Attribute<?> attr : attrs) {
						json.put(attr.getName(), getJSONObjectValue(attr));
					}
				}

				Map<String, List<IGenericTO>> relaMap = to.getRelationsMap();
				if (relaMap != null && relaMap.size() > 0) {
					Map.Entry<String, List<IGenericTO>> entry;
					String entryName;
					List<IGenericTO> entryTos;
					for (Iterator<Map.Entry<String, List<IGenericTO>>> iter = relaMap
							.entrySet().iterator(); iter.hasNext();) {
						entry = iter.next();
						entryName = entry.getKey();
						entryTos = entry.getValue();
						if (entryTos != null && entryTos.size() > 0) {
							JSONArray array = new JSONArray();
							for (IGenericTO entryTo : entryTos) {
								array.put(createJSONObject(entryTo));
							}
							json.put(entryName, array);
						}
					}
				}
			}

			return json;

		} catch (SinoAttributeException e) {
			log.error("通过TO创建JSON对象出现错误");
			throw e;
		} catch (JSONException e) {
			log.error("通过TO创建JSON对象出现错误");
			throw new SinoAttributeException("通过TO创建JSON对象出现错误");
		}
	}

	/**
	 * 通过Attribute对象获得Json对象值
	 * 
	 * @param attr
	 * @return
	 * @throws SinoAttributeException
	 */
	private static Object getJSONObjectValue(Attribute<?> attr)
			throws SinoAttributeException {
		if (attr.getType() == CommonAttributeType.TYPE_INTEGER
				|| attr.getType() == CommonAttributeType.TYPE_NUMBER
				|| attr.getType() == CommonAttributeType.TYPE_BOOLEAN) {
			return (Object) attr.getValue();
		}
		return attr.convertToString();
	}

	/**
	 * 通过JSONObject对象，创建一个通用TO对象
	 * 
	 * @param jo
	 * @return
	 * @throws SinoAttributeException
	 */
	public static IGenericTO createGenericTO(JSONObject jo)
			throws SinoAttributeException {
		IGenericTO to = createGenericTO();

		Iterator<?> keys = jo.keys();

		String attrKey;
		Object attrJo;
		while (keys.hasNext()) {
			attrKey = (String) keys.next();
			attrJo = jo.opt(attrKey);
			if (attrJo != null) {
				// 如果是JSONObject对象
				if (attrJo instanceof JSONObject) {
					to.addRelation(attrKey,
							createGenericTO((JSONObject) attrJo));
				}
				// 如果是JSONArray对象
				else if (attrJo instanceof JSONArray) {
					to
							.addRelation(attrKey,
									createGenericTO((JSONArray) attrJo));
				}
				// 如果是普通对象
				else {
					Attribute<?> attr = createToAttributeByValue(attrJo);
					attr.setName(attrKey);
					attr.setConcept(attrKey);
					to.add(attr);
				}
			}
		}

		return to;
	}

	/**
	 * 沉默的通过路径获得属性
	 * 
	 * @param to
	 * @param path
	 * @return
	 */
	public static Attribute<?> getAttributeByPathSilent(IGenericTO to,
			String path) {
		try {
			return getAttriubteByPath(to, path);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 通过名称获得内容属性
	 * 
	 * @param to
	 * @param name
	 * @return
	 * @throws SinoAttributeException
	 */
	public static Attribute<?> getContentAttriubteByName(IGenericTO to,
			String name) throws SinoAttributeException {
		return getAttributeByPathSilent(to, ATTRIBUTE_CONTENT_PREFIX + name);
	}

	/**
	 * 通过路径获得属性
	 * 
	 * @param to
	 * @param path
	 * @return
	 * @throws SinoAttributeException
	 */
	public static Attribute<?> getAttriubteByPath(IGenericTO to, String path)
			throws SinoAttributeException {
		// TODO 正则表达式验证path-----eg. content[0]->configSceneId
		try {
			String[] pathArr = path.split("->");
			IGenericTO tmpTo = to;
			if (tmpTo == null || Const.isEmpty(path))
				return null;
			String name;
			int index;
			int temp;
			for (int i = 0; i < pathArr.length - 1; i++) {
				temp = pathArr[i].lastIndexOf("[");
				if (temp < 0) {
					name = pathArr[i];
					index = 0;
				} else {
					name = pathArr[i].substring(0, temp);
					index = Integer.parseInt(pathArr[i].substring(temp + 1,
							pathArr[i].length() - 1));
				}
				tmpTo = tmpTo.getRelations(name).get(index);
				if (tmpTo == null)
					return null;
			}
			return tmpTo.getAttributeByName(pathArr[pathArr.length - 1]);
		} catch (Exception ex) {
			throw new SinoAttributeException("通过路径获得属性出现错误！");
		}
	}

	/**
	 * 通过JSONArray对象，创建一个通用TO对象
	 * 
	 * @param ja
	 * @return
	 * @throws SinoAttributeException
	 */
	public static IGenericTO createGenericTO(JSONArray ja)
			throws SinoAttributeException {
		IGenericTO to = createGenericTO();

		Object attrJo;
		for (int i = 0; i < ja.length(); i++) {
			attrJo = ja.opt(i);
			if (attrJo != null) {
				// 如果是JSONObject对象
				if (attrJo instanceof JSONObject) {
					to.addRelation(String.valueOf(i),
							createGenericTO((JSONObject) attrJo));
				}
				// 如果是JSONArray对象
				else if (attrJo instanceof JSONArray) {
					to.addRelation(String.valueOf(i),
							createGenericTO((JSONArray) attrJo));
				}
				// 如果是普通对象
				else {
					Attribute<?> attr = createToAttributeByValue(attrJo);
					attr.setName(String.valueOf(i));
					attr.setConcept(String.valueOf(i));
					to.add(attr);
				}
			}
		}

		return to;
	}

	public static Attribute<?> createToAttribute(Class<?> clazz)
			throws SinoAttributeException {
		try {
			return (Attribute<?>) ReflectionUtils.newInstance(clazz);
		} catch (Exception e) {
			log.error("创建To属性出现错误(createToAttribute):" + clazz);
			throw new SinoAttributeException("创建To属性出现错误(createToAttribute)");
		}
	}

	public static Attribute<?> createToAttribute(String className)
			throws SinoAttributeException {
		try {
			return (Attribute<?>) ReflectionUtils.newInstance(className);
		} catch (Exception e) {
			log.error("创建To属性出现错误(createToAttribute):" + className);
			throw new SinoAttributeException("创建To属性出现错误(createToAttribute)");
		}
	}

	public static Attribute<?> createToAttribute(CommonAttributeType type)
			throws SinoAttributeException {
		if (type.getToAttributeClass() != null) {
			return createToAttribute(type.getToAttributeClass());
		}
		return null;
	}

	public static Attribute<?> createToAttributeByValue(Object obj)
			throws SinoAttributeException {
		Class<?> clazz = CommonAttributeType.getTypeByObject(obj)
				.getToAttributeClass();
		if (clazz != null) {
			Attribute<?> attr = createToAttribute(clazz);
			try {
				attr.instantiateFromObject(obj);
				return attr;
			} catch (SinoAttributeException e) {
				log.error("创建To属性出现错误(createToAttribute)");
				throw e;
			}
		}
		return null;
	}

}
